import json, time
from time import timezone
from django import http
from decimal import Decimal
from datetime import datetime
from django.conf import settings
from django.db import transaction
from django.shortcuts import render
from django.views.generic import View
from django_redis import get_redis_connection

from goods.models import SKU
from meiduo.models import Address
from urtils.response_code import RETCODE
from urtils.Mixin import LoginRequiredMixin
from urtils.view import LoginRequiredJSONMixin
from order.models import OrderInfo, OrderGoods


# class UserOrderInfoView(LoginRequiredMixin, View):
#     """展示订单信息"""
#     def get(self, request):
#
#         pass


class OrderSuccessView(LoginRequiredJSONMixin, View):
    """提交订单成功"""
    def get(self, request):
        order_id = request.GET.get("order_id")
        payment_amount = request.GET.get("payment_amount")
        pay_method = request.GET.get("pay_method")

        # 构造函数
        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method,
        }
        return render(request, 'order_success.html', context)


class OrderCommitView(LoginRequiredJSONMixin, View):
    """订单提交"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 保存订单信息
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        # 验证数据
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden("数据不完整")

        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return http.HttpResponseForbidden("参数address_id错误")
        # 判断pay_method是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('参数pay_method错误')

        # 开启一次事物
        with transaction.atomic():

            # 创建事物原始点
            save_id = transaction.savepoint()

            # 暴力回滚
            try:
                # 获取登录用户信息
                user = request.user
                # 设置订单号
                t = time.localtime()
                order_id = '%04d%02d%02d%02d%02d%02d%09d' % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, user.id)

                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal(0.00),
                    freight=Decimal(10.00),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND'],
                )

                # 保存订单商品信息
                # 查询redis里的商品勾选信息
                redis_conn = get_redis_connection('carts')
                # 购物车的所有数据
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                # 购物车被勾选的数据
                redis_selected = redis_conn.smembers('selected_%s' % user.id)
                pl = redis_conn.pipeline()
                # 构造购物车中被勾选的数据
                redis_dict = {}
                for sku_id in redis_selected:
                    redis_dict[int(sku_id)] = int(redis_cart[sku_id])

                # 获取被勾选的id
                sku_ids = redis_dict.keys()
                for sku_id in sku_ids:
                    while True:
                        # 读取购物车商品信息
                        sku = SKU.objects.get(id=sku_id)
                        # 读取原始库存和销量
                        origin_stock = sku.stock  # 库存
                        origin_sales = sku.sales  # 销量

                        # 获取要提交订单的数量
                        sku_count = redis_dict[sku.id]

                        # 判断购买的商品是否大于库存
                        if sku_count > sku.stock:
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 减库存　加销量
                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()

                        new_stock = origin_stock-sku_count
                        new_sales = origin_sales+sku_count
                        # 使用乐观锁并发下单
                        # 失败结果为0
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        # 如果下单失败，但是库存足够时，继续下单，直到下单成功或者库存不足为止
                        if result == 0:
                            # continue 跳出此次循环不执行下面的代码，继续下一轮循环
                            continue

                        # 加销量
                        sku.spu.sales += sku_count
                        sku.spu.save()

                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )

                        # 累加订单到数量和总价到订单信息表
                        order.total_count = sku_count
                        order.total_amount += sku_count * sku.price

                        # 下单成功或者失败就跳出循环
                        break

                order.total_amount += order.freight
                order.save()

                # 清除购物车中已结算的商品
                pl.hdel('carts_%s' % user.id, *redis_selected)
                pl.srem('selected_%s' % user.id, *redis_selected)
                pl.execute()
            except Exception as e:
                transaction.savepoint_rollback(save_id)

            # 提交事物
            transaction.savepoint_commit(save_id)

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'order_id': order_id})


class OrderSettlementView(LoginRequiredMixin, View):
    """结算订单"""
    def get(self, request):
        """提供用户登录页面"""
        # 获取登录用户信息
        user = request.user
        # 获取收货地址
        try:
            address = Address.objects.filter(user=user, is_deleted=False)
        except Exception as e:
            address = None

        # 获取商品信息    连接数据库
        redis_coon = get_redis_connection('carts')
        # 获取redis数据库的全部信息
        redis_cart = redis_coon.hgetall('carts_%s' % user.id)
        # 获取redis被勾选的信息
        redis_selected = redis_coon.smembers('selected_%s' % user.id)
        # 构造出购物车中被勾选的数据
        redis_dict = {}
        # 遍历redis_selected
        for sku_id in redis_selected:
            redis_dict[int(sku_id)] = int(redis_cart[sku_id])

        # 查询购物车需要的内容
        # 商品数量
        total_count = 0
        # 商品价格
        total_amount = Decimal(0.00)
        # 运费
        freight = Decimal('10.00')
        # 遍历redis_dict 区中里面的sku_id 和　count
        sku_ids = redis_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            sku.count = redis_dict[sku.id]
            sku.amount = sku.price * sku.count
            # 累加数量和金额
            total_count += sku.count
            total_amount += sku.price * sku.count

        # 构造上下文
        context = {
            'addresses': address,   # 收货地址
            'skus': skus,         # 商品信息
            'total_count': total_count,  # 商品数量
            'total_amount': total_amount,     # 商品价格
            'freight': freight,      # 运费
            'payment_amount': freight + total_amount,    # 总价
            'FDFS_BASE_URL': settings.FDFS_BASE_URL
        }
        return render(request, 'place_order.html', context)
